]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
extensionDownloader: Add update/blacklist support for extensions
authorJasper St. Pierre <jstpierre@mecheye.net>
Wed, 27 Jun 2012 00:47:44 +0000 (20:47 -0400)
committerJasper St. Pierre <jstpierre@mecheye.net>
Tue, 10 Jul 2012 18:36:41 +0000 (14:36 -0400)
This is a bare-bones copy/replace. It does not implement ChangeLog
support. If we cannot get System Updates integration, I will implement
notification support.

https://bugzilla.gnome.org/show_bug.cgi?id=679099

js/misc/fileUtils.js
js/ui/extensionDownloader.js
js/ui/shellDBus.js

index 7466be87aa5f6bf0c04da9cba1af1abd1695ab1d..4e620254b36c8143a0f49eead35a6ac887fae167 100644 (file)
@@ -28,7 +28,7 @@ function deleteGFile(file) {
     return file['delete'](null);
 }
 
-function recursivelyDeleteDir(dir) {
+function recursivelyDeleteDir(dir, deleteParent) {
     let children = dir.enumerate_children('standard::name,standard::type',
                                           Gio.FileQueryInfoFlags.NONE, null);
 
@@ -39,8 +39,29 @@ function recursivelyDeleteDir(dir) {
         if (type == Gio.FileType.REGULAR)
             deleteGFile(child);
         else if (type == Gio.FileType.DIRECTORY)
-            recursivelyDeleteDir(child);
+            recursivelyDeleteDir(child, true);
     }
 
-    deleteGFile(dir);
+    if (deleteParent)
+        deleteGFile(dir);
+}
+
+function recursivelyMoveDir(srcDir, destDir) {
+    let children = srcDir.enumerate_children('standard::name,standard::type',
+                                             Gio.FileQueryInfoFlags.NONE, null);
+
+    if (!destDir.query_exists(null))
+        destDir.make_directory_with_parents(null);
+
+    let info, child;
+    while ((info = children.next_file(null)) != null) {
+        let type = info.get_file_type();
+        let srcChild = srcDir.get_child(info.get_name());
+        let destChild = destDir.get_child(info.get_name());
+        log([srcChild.get_path(), destChild.get_path()]);
+        if (type == Gio.FileType.REGULAR)
+            srcChild.move(destChild, Gio.FileCopyFlags.NONE, null, null);
+        else if (type == Gio.FileType.DIRECTORY)
+            recursivelyMoveDir(srcChild, destChild);
+    }
 }
index 4dd683d892d55af1cd8ff46f68f4301c75a04a4e..83f8a36fc303c433b0e8dc30462e6a4ea04016ab 100644 (file)
@@ -7,6 +7,7 @@ const GLib = imports.gi.GLib;
 const Gio = imports.gi.Gio;
 const Soup = imports.gi.Soup;
 const St = imports.gi.St;
+const Shell = imports.gi.Shell;
 
 const Config = imports.misc.config;
 const ExtensionUtils = imports.misc.extensionUtils;
@@ -18,7 +19,8 @@ const _signals = ExtensionSystem._signals;
 
 const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
 const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
-const REPOSITORY_URL_INFO =     REPOSITORY_URL_BASE + '/extension-info/';
+const REPOSITORY_URL_INFO     = REPOSITORY_URL_BASE + '/extension-info/';
+const REPOSITORY_URL_UPDATE   = REPOSITORY_URL_BASE + '/update-info/';
 
 let _httpSession;
 
@@ -61,17 +63,16 @@ function uninstallExtension(uuid) {
     if (!ExtensionSystem.unloadExtension(uuid))
         return false;
 
-    FileUtils.recursivelyDeleteDir(extension.dir);
+    FileUtils.recursivelyDeleteDir(extension.dir, true);
     return true;
 }
 
-function gotExtensionZipFile(session, message, uuid, callback, errback) {
+function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
     if (message.status_code != Soup.KnownStatusCode.OK) {
         errback('DownloadExtensionError', message.status_code);
         return;
     }
 
-    let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
     try {
         if (!dir.query_exists(null))
             dir.make_directory_with_parents(null);
@@ -105,6 +106,81 @@ function gotExtensionZipFile(session, message, uuid, callback, errback) {
     });
 }
 
+function updateExtension(uuid) {
+    // This gets a bit tricky. We want the update to be seamless -
+    // if we have any error during downloading or extracting, we
+    // want to not unload the current version.
+
+    let oldExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
+    let newExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
+
+    let params = { shell_version: Config.PACKAGE_VERSION };
+
+    let url = REPOSITORY_URL_DOWNLOAD.format(uuid);
+    let message = Soup.form_request_new_from_hash('GET', url, params);
+
+    _httpSession.queue_message(message, Lang.bind(this, function(session, message) {
+        gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, function() {
+            let oldExtension = ExtensionUtils.extensions[uuid];
+            let extensionDir = oldExtension.dir;
+
+            if (!ExtensionSystem.unloadExtension(uuid))
+                return;
+
+            FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
+            FileUtils.recursivelyMoveDir(newExtensionTmpDir, extensionDir);
+
+            let extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER);
+
+            try {
+                ExtensionSystem.loadExtension(extension);
+            } catch(e) {
+                ExtensionSystem.unloadExtension(uuid);
+
+                logError(e, 'Error loading extension %s'.format(uuid));
+
+                FileUtils.recursivelyDeleteDir(extensionDir, false);
+                FileUtils.recursivelyMoveDir(oldExtensionTmpDir, extensionDir);
+
+                // Restore what was there before. We can't do much if we
+                // fail here.
+                ExtensionSystem.loadExtension(oldExtension);
+                return;
+            }
+
+            FileUtils.recursivelyDeleteDir(oldExtensionTmpDir, true);
+        }, function(code, message) {
+            log('Error while updating extension %s: %s (%s)'.format(uuid, code, message ? message : ''));
+        });
+    }));
+}
+
+function checkForUpdates() {
+    let metadatas = {};
+    for (let uuid in ExtensionUtils.extensions) {
+        metadatas[uuid] = ExtensionUtils.extensions[uuid].metadata;
+    }
+
+    let params = { shell_version: Config.PACKAGE_VERSION,
+                   installed: JSON.stringify(metadatas) };
+
+    let url = REPOSITORY_URL_UPDATE;
+    let message = Soup.form_request_new_from_hash('GET', url, params);
+    _httpSession.queue_message(message, function(session, message) {
+        if (message.status_code != Soup.KnownStatusCode.OK)
+            return;
+
+        let operations = JSON.parse(message.response_body.data);
+        for (let uuid in operations) {
+            let operation = operations[uuid];
+            if (operation == 'blacklist')
+                uninstallExtension(uuid);
+            else if (operation == 'upgrade' || operation == 'downgrade')
+                updateExtension(uuid);
+        }
+    });
+}
+
 const InstallExtensionDialog = new Lang.Class({
     Name: 'InstallExtensionDialog',
     Extends: ModalDialog.ModalDialog,
@@ -149,6 +225,7 @@ const InstallExtensionDialog = new Lang.Class({
         let message = Soup.form_request_new_from_hash('GET', url, params);
 
         let uuid = this._uuid;
+        let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
         let invocation = this._invocation;
         function errback(code, message) {
             invocation.return_dbus_error('org.gnome.Shell.' + code, message ? message.toString() : '');
@@ -176,7 +253,7 @@ const InstallExtensionDialog = new Lang.Class({
         }
 
         _httpSession.queue_message(message, Lang.bind(this, function(session, message) {
-            gotExtensionZipFile(session, message, uuid, callback, errback);
+            gotExtensionZipFile(session, message, uuid, dir, callback, errback);
         }));
 
         this.close(global.get_current_time());
index 83074e4ba50655c9a3e45e70e84e849e44b02d66..661818ed83386175be8f26443a35b5cbff3b8027 100644 (file)
@@ -214,6 +214,8 @@ const GnomeShellExtensionsIface = <interface name="org.gnome.Shell.Extensions">
 <method name="ReloadExtension">
     <arg type="s" direction="in" name="uuid"/>
 </method>
+<method name="CheckForUpdates">
+</method>
 <property name="ShellVersion" type="s" access="read" />
 </interface>;
 
@@ -306,6 +308,10 @@ const GnomeShellExtensions = new Lang.Class({
         ExtensionSystem.loadExtension(uuid);
     },
 
+    CheckForUpdates: function() {
+        ExtensionDownloader.checkForUpdates();
+    },
+
     ShellVersion: Config.PACKAGE_VERSION,
 
     _extensionStateChanged: function(_, newState) {